package n7.restaurant.java.Entity;

import java.util.ArrayList;
import java.util.Iterator;

import n7.restaurant.java.Enum.Etat_Client;
import n7.restaurant.java.Swing.Swing;

public class Client implements Utilisateur, Runnable {
	private String id;
	private Position position;
	private String toString;

	private ArrayList<Etat_Mental> etat_mentaux = new ArrayList<Etat_Mental>();
	public static ArrayList<Client> clients = new ArrayList<Client>();
	private Etat_Client etat;
	private int idServeur;

	public String getToString() {
		return toString;
	}

	public void setToString(String toString) {
		this.toString = toString;
	}

	public int getIdServeur() {
		return idServeur;
	}

	public void setIdServeur(int idServeur) {
		this.idServeur = idServeur;
	}

	public Etat_Client getEtat() {
		return etat;
	}

	public void setEtat(Etat_Client etat) {
		this.etat = etat;
	}

	public Client(String id, Position position) {
		super();
		this.id = id;
		this.position = position;
		this.etat = Etat_Client.init;
	}

	public Client() {
		this.position = new Position();
		this.etat = Etat_Client.init;
	}

	public Position getPosition() {
		return position;
	}

	public void setPosition(Position position) {
		this.position = position;
	}

	public String getId() {
		return id;
	}

	public int getNumero(String id) {
		return Integer.parseInt(this.getId().substring(1, 2));
	}

	public void setId(String id) {
		this.id = id;
	}

	/**
	 * imprimer les etat mentaux
	 * */
	@Override
	public String toString() {
		String returnString = "\n" + this.getId() + "\n";
		/* returnString += "Client [id=" + id + ", " + position; */
		for (int i = 0; i < this.etat_mentaux.size(); i++) {
			Etat_Mental e = this.etat_mentaux.get(i);
			returnString += e.toString() + "\n";
		}
		/* returnString += "]"; */
		returnString += "knowref(" + this.getId() + ",etat("
				+this.getId()  + ")="+this.getEtat().toString()+")";
		return returnString;
	}

	/**
	 * le methode du thread
	 * */
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			// depend l'etat_mental
			if (this.getEtat() == Etat_Client.init && wantDemandeMenu()) {
				demandeMenu();
			} else if (this.getEtat() == Etat_Client.waitServeur
					&& isServeurArrive()) {
				// depend l'etat et l'etat mental
				/* System.out.println(this); */
				commandMenu();
				/* System.out.println(this); */
			}
			// else
			// System.out.println("No");
		}
	}

	/**
	 * Si le serveur arrive apres de lui ou pas.
	 * */
	public boolean isServeurArrive() {
		// TODO Auto-generated method stub
		// cherche
		// know(C4, arrive(SV2))
		synchronized (this) {
			for (Iterator<Etat_Mental> i = this.etat_mentaux.iterator(); i
					.hasNext();) {
				Etat_Mental e = i.next();
				if (e.getDescription().equalsIgnoreCase("know")
						&& e.getFormule().contains("arrive")) {

					// Swing.TAP[this.getNumero(id)]+=", sait_que("+this.id+","+e.getFormule().substring(7,
					// 9)+",arrive_a_table("+e.getFormule().substring(7,
					// 9)+"))";
					return true;
				}
			}
			return false;
		}
	}

	public ArrayList<Etat_Mental> getEtat_mentaux() {
		return etat_mentaux;
	}

	public void setEtat_mentaux(ArrayList<Etat_Mental> etat_mentaux) {
		this.etat_mentaux = etat_mentaux;
	}

	/**
	 * Le client demande un menu au serveur.
	 * 
	 * */
	@Override
	public void demandeMenu() {
		/*
		 * System.out.println("Action: demandeMenu(" + this.getId() + "," + "_"
		 * + ")");
		 */
		// Action
		Swing.TAP[this.getNumero(id)] += "informer(" + this.id
				+ ",_,veut_commande_menu)";
		synchronized (Client.class) {
			// Informer tous les serveurs.
			for (Iterator<Serveur> i = Serveur.serveurs.iterator(); i.hasNext();) {
				Serveur s = i.next();
				Etat_Mental e = new Etat_Mental("knowref", s,
						"wantDemandeMenu(" + this.getId() + ")=true");
				/* System.out.println(e); */
				s.addEtatMental(e);
			}

			// Supprime l'etat mental qui veut dire qu'il veut demande un menu
			// parce
			// qu'il a fini de demande.
			for (Iterator<Etat_Mental> i = this.etat_mentaux.iterator(); i
					.hasNext();) {
				Etat_Mental e = i.next();
				// Cherche les mots 'veut' et 'demandeMenu(this.id)'
				if (e.getDescription().equalsIgnoreCase("want")
						&& e.getFormule().equals("demande_menu")) {
					i.remove();
				}
			}
		}
	}

	/**
	 * Cherche si il y a l'etat mental qui signifie qu'il veut demande un menu.
	 * */
	public boolean wantDemandeMenu() {
		// etat mentaux sont null, c'est sur qu'il n'a pas demande.
		if (this.etat_mentaux.size() == 0) {
			return false;
		}
		// sinon
		else {
			// Iteration
			for (Iterator<Etat_Mental> i = this.etat_mentaux.iterator(); i
					.hasNext();) {
				Etat_Mental e = i.next();
				// Cherche les mots 'veut' et 'demandeMenu(this.id)'
				// formule: [veut(C4, demandeMenu(C4))]
				if (e.getDescription().equalsIgnoreCase("want")
						&& e.getFormule().equals("demande_menu")) {
					this.setEtat(Etat_Client.waitServeur);
					return true;
				}
			}
			return false;
		}
	}

	/**
	 * Ajouter un etat mental au etat mentaux.
	 * */
	public void addEtatMental(Etat_Mental e) {
		this.etat_mentaux.add(e);
	}

	/**
	 * Command un menu.
	 * */
	public void commandMenu() {
		// Choisir un numero de menu
		int idMenu = (int) (Math.random() * 3);

		// insert into Client: want(C4, commande(M0))
		Etat_Mental e = new Etat_Mental();
		e.setY(this);
		e.setDescription("know");
		e.setFormule("commande(" + Menu.menus.get(idMenu).getId() + ")");
		this.addEtatMental(e);

		// Trouver le numero du serveur qui me sert.
		for (Iterator<Etat_Mental> i = this.etat_mentaux.iterator(); i
				.hasNext();) {
			Etat_Mental em = i.next();
			// find know(C4, arrive(SV2)) for search id
			if (em.getFormule().contains("arrive")) {
				this.setIdServeur(Integer.parseInt(em.getFormule().substring(9,
						10)));
			}
			// delete
			// know(C4, venir_livrer_menu(SV2))
			// know(C4, arrive(SV2))
			// want(SV1, livrer_menu(C2))
			// know(C2, arrive(SV1))
			if (em.getFormule().contains("SV")) {
				i.remove();
			}
		}

		// informer serveur qu'est que j'ai besoin
		// know(SV1, commande(C4,M0))
		Serveur s = Serveur.serveurs.get(getIdServeur());
		e = new Etat_Mental();
		e.setAgent_X(s);
		e.setDescription("know");
		e.setFormule("commande(" + this.getId() + "," + "M" + idMenu + ")");
		s.addEtatMental(e);
		// insert
		// want(SVi, knowref(GC0,commande(C4)=M0)));
		e = new Etat_Mental();
		e.setAgent_X(s);
		e.setDescription("want");
		e.setFormule("knowref(" + Chef.grand_chef.getId() + ",commande("
				+ this.getId() + ")=" + "M" + idMenu + ")");
		s.addEtatMental(e);

		// Action:
		Swing.TAP[this.getNumero(id)] += ", dit_que(" + this.id + ","
				+ s.getId() + ",commande(" + this.id + ",M" + idMenu + "))";
		// supprimer
		// want(SV1, livrer_menu(C0))
		for (Iterator<Etat_Mental> i = s.getEtat_mentaux().iterator(); i
				.hasNext();) {
			Etat_Mental em = i.next();
			if (em.getDescription().equalsIgnoreCase("want")
					&& em.getFormule().equalsIgnoreCase(
							"livrer_menu(" + this.getId() + ")")) {
				i.remove();
			}
		}
		/* System.out.println(s); */
		// Le client attend l'entree.
		this.setEtat(Etat_Client.waitEntree);
		/* System.out.println(this); */
	}
}
